﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Data;
using DGen;
using NLog;

namespace Tab2Sql.Classes.Convertors
{
    /// <summary>
    ///
    /// </summary>
    public class Delimiter
    {

        private static Logger logger = LogManager.GetCurrentClassLogger ();
        private string _current;

        private int[] _fixedWidths;
        /// <summary>
        /// Default constructor.
        /// </summary>

        public Delimiter ()
        {
            scanRunCount = 0;
            
            _current = @"\t";
            
            
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="userDelimiter">
        /// A <see cref="System.String"/>
        /// </param>
        public Delimiter (string userDelimiter)
        {
            scanRunCount = 0;
            _current = userDelimiter;
            
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="userDelimiter">
        /// A <see cref="System.Char"/>
        /// </param>
        public Delimiter (char userDelimiter)
        {
            scanRunCount = 0;
            _current = userDelimiter.ToString ();
            
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="useFixedWidth">
        /// A <see cref="System.Boolean"/>
        /// </param>
        /// <param name="inputString">
        /// A <see cref="System.String[]"/>
        /// </param>
        public Delimiter (bool useFixedWidth, string[] inputString)
        {
            scanRunCount = 0;
            
            ArrayList array = new ArrayList ();
            int x, y;
            x = 0;
            y = 0;
            
            
            
            string line = inputString[0];
            char[] c = line.ToCharArray ();
            for (int i = 0; i < c.Count (); i++)
            {
                if (Char.IsWhiteSpace (c[i]))
                {
                    y = x;
                    x = i;
                    if (x > y + 1)
                    {
                        array.Add (i);
                    }
                }
            }
            
            _fixedWidths = (int[])array.ToArray (typeof(System.Int32));
            
            
            
        }

        DataTable scanResultTable;
        Hashtable scanResultHash;
        StringBuilder scanResult;
        Dictionary<int, int> delimeterPlacements;
        int scanRunCount;
        int delimitersFoundLastTime = -1;
        string scanDelimiter;
        ArrayList scanDelimiterHistory;







        private void setupScanResultTable ()
        {
            scanResultTable = new DataTable ();
            scanResultTable.Columns.Add ("id", typeof(Int32));
            scanResultTable.Columns.Add ("line", typeof(Int32));
            scanResultTable.Columns.Add ("columnName", typeof(Int32));
            scanResultTable.Columns.Add ("delimiterOccurance", typeof(Int32));
            scanResultTable.BeginLoadData ();
        }


        /// <summary>
        /// Process input text and produce basic information on delimiter frequency/position per line
        /// </summary>
        /// <param name="inLines">
        /// A <see cref="System.String[]"/>
        /// </param>
        /// <param name="d">
        /// A <see cref="System.String"/>
        /// </param>
        /// <param name="classMethod">
        /// A <see cref="System.Boolean"/>
        /// </param>
        /// <returns>
        /// A <see cref="System.String"/>
        /// </returns>
        public string DelimiterScan (ref string[] inLines, string d, bool classMethod)
        {
            scanDelimiter = d;
            scanDelimiterHistory = new ArrayList ();
            scanDelimiterHistory.Add (d);


            int r = -1;
            do
            {
                r = delimiterScanProcess (ref inLines);
            } while (r < 0);
            produceScanResultText ();
            return scanResult.ToString ();
            
            
            
            
        }
        private void produceScanResultText ()
        {
            
            if (delimitersFoundLastTime == -100)
            {
                scanResult.AppendLine ("We have given up as no delimiters could be found.");
                return;
                
            }
            
            StringBuilder firstTable = new StringBuilder ();
            StringBuilder secondTable = new StringBuilder ();
            firstTable.AppendLine ("Row     DelimiterCount");
            firstTable.AppendLine (DText.ObjectToString.DictionaryToString (delimeterPlacements, true));
            secondTable.AppendLine (DText.ObjectToString.DataTableToString (scanResultTable, DGen.Constants.TAB));
            
            
            scanResult.AppendLine (firstTable.ToString ());
            scanResult.AppendLine (secondTable.ToString ());
            
        }
        /// <summary>
        /// Crude analysis of input text to determine delimiter instances per line. Used to try and work out which rows are breaking imports by rogue values.
        /// Does not deal with text quoted or escaped delimiters - i.e. the DelimiterCount is a literal translation of that character on that line.
        /// </summary>
        /// <param name="inLines"></param>


        /// <returns></returns>
        ///

        private int delimiterScanProcess (ref string[] inLines)
        {
            logger.Info ("delimiterScanProcess kicked off. scanRunCount:{0}. scanDelimiter:{1}.scanDelimiterHistory:{2}", scanRunCount, scanDelimiter,scanDelimiterHistory.Count);

            
            scanResult = new StringBuilder ();
            
            setupScanResultTable ();
            
            
            scanResultHash = new Hashtable ();
            
            
            int lCount = 0;
            delimeterPlacements = new Dictionary<int, int> ();
            
            
            
            
            
            

            int globalCounter = 0;
            foreach (string Line in inLines)
            {
                
                if (Line.Trim ().Length == 0)
                {
                    lCount++;
                } else
                {
                    string tmpLine = Line;
                    int posX = 0;
                    int uCount = DText.CountOccurences (scanDelimiter, tmpLine);
                    delimeterPlacements.Add (lCount, uCount);
                    
                    for (int i = 0; i < uCount; i++)
                    {
                        globalCounter++;
                        object[] moo = { globalCounter, lCount, posX, i };
                        DataRow dr = scanResultTable.NewRow ();
                        dr.ItemArray = moo;
                        scanResultTable.Rows.Add (dr);
                        
                        posX = DGen.DText.GetCharPosition (tmpLine, scanDelimiter, i);
                        if (!scanResultHash.ContainsKey (posX))
                        {
                            scanResultHash.Add (posX, lCount);
                        }
                    }
                    lCount++;
                }
                
                
            }
            scanResultTable.AcceptChanges ();
            
            scanRunCount++;
            
            if (globalCounter > 0)
            {
                delimitersFoundLastTime = globalCounter;
                
                return 0;
                
            }
            
            if (globalCounter == 0 && scanRunCount < 4)
            {
                scanDelimiterHistory.Add(scanDelimiter);

                /*
                 0=User supplied delimiter
                 1=Tab
                 2=Comma
                 3=Pipe
                 4=Give up.
                */
                string[] delimiterOptions=new string[]{"\t",",",@"\|"};




                int optionsLeft=0;

                foreach (var item in delimiterOptions)
                {
                    if (!scanDelimiterHistory.Contains(item))
                    {
                        optionsLeft=1;

                        scanDelimiter=item.ToString();
                    }

                }
                if (optionsLeft==1)
                {

                    return -2;
                }
                else {return -100;}

                //do again.

            } else
            {
                delimitersFoundLastTime = -100;
                
                
                return 100;
                //give up.
                
            }
        }


    }
}

